using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using OpenComposite.Base.Designer;
using OpenComposite.EII.Repository;
using System.Xml.Serialization;
using System.Xml.Schema;
using System.Xml;
using System.Data;
using OpenComposite.Repository.Properties;

namespace OpenComposite.EII.Designer.BObjects
{
	public class BusinessObjectSymbol : CollapsableSymbol, IXmlSerializable, IRepositoryItemSymbol
	{
		#region Initialization
		public BusinessObjectSymbol()
		{
			init();
		}
		private void init()
		{
			this.BeginUpdate();

			// symbol settings
			this.BackColor = Color.AliceBlue;
			this.BackBrushMode = BackgroundBrushMode.Solid;

			this.Border = BorderType.Rectangle;
			this.BorderWidth = 1;
			this.BorderColor = Color.Gray;
			this.Size = new Size(150, 200);
			this.MinimumSize = new Size(100, _iHeaderHeight);

			//this.Name = "businessObject" + GetCount(typeof(BusinessObjectSymbol));
			this.Text = this.Name;

			this.CollapseSign = CollapseSign.DoubleArrow;

			this.CollapsedSize = new Size(150, _iHeaderHeight);
			this.CollapsedBackColor = Color.AliceBlue;
			this.CollapsedBackColor2 = Color.AliceBlue;
			this.CollapsedBorderColor = Color.Gray;

			this.ExpandedSize = new Size(150, 200);
			this.ExpandedBackColor = Color.AliceBlue;
			this.ExpandedBackColor2 = Color.AliceBlue;
			this.ExpandedBorderColor = Color.Gray;
			//
			// NameTextBox
			//
			this.NameTextBox.AutoSize = false;
			this.NameTextBox.Bounds = Rectangle.FromLTRB(20, 0, this.NameTextBox.Right - 20, this.NameTextBox.Height);
			this.NameTextBox.BackColor = Color.AliceBlue;
			this.NameTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;

			Rectangle rC = this.CalculateClientArea();
			//
			// _listView
			//
			_listView = new OpenComposite.Base.Designer.ListView();
			_listView.Bounds = new Rectangle(0, _iHeaderHeight, rC.Width, rC.Height - _iHeaderHeight);
			_listView.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left |
				System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Top;

			// add event handlers
			_listView.GotFocus += new EventHandler(_listView_GotFocus);
			_listView.FieldMoved += new EventHandler<FieldMoveEventArgs>(_listView_FieldMoved);

			// add columns
			_listView.Columns.Add(new Column("Name", Column.ColumnType.TextBox));
			_listView.Columns.Add(new Column("DataType", Column.ColumnType.ComboBox));

			// add to business object symbol
			this.Controls.Add(_listView);

			// additional settings
			_listView.BackColor = Color.White;

			//
			// _contextList
			//
			_contextList = new ContextMenuStrip();
			_contextList.Items.Add("Edit Field...", null, new EventHandler(contextList_EditField));
			_contextList.Items.Add("New Field...", null, new EventHandler(contextList_NewField));
			_contextList.Items.Add(new ToolStripSeparator());
			_contextList.Items.Add("Remove Field", null, new EventHandler(contextList_RemoveField));
			_contextList.Items.Add(new ToolStripSeparator());
			_contextList.Items.Add("Move Up", Resources.bmp_moveup, new EventHandler(contextList_MoveUpField))
				.ImageTransparentColor = Color.Magenta;
			_contextList.Items.Add("Move Down", Resources.bmp_movedown, new EventHandler(contextList_MoveDownField))
				.ImageTransparentColor = Color.Magenta;

			_contextList.Opening += new System.ComponentModel.CancelEventHandler(contextList_Opening);

			_listView.ContextMenuStrip = _contextList;

			//
			// _contextBObj
			//
			_contextBObj = new ContextMenuStrip();
			_contextBObj.Items.Add("Remove Business Object", null, new EventHandler(contextBObj_Remove));
			_contextBObj.Items.Add(new ToolStripSeparator());
			_contextBObj.Items.Add("Delete Business Object", OpenComposite.Repository.Properties.Resources.ico_delete_16x.ToBitmap(),
								   new EventHandler(contextBObj_Delete));

			_contextBObj.Opening += new System.ComponentModel.CancelEventHandler(contextBObj_Opening);

			this.ContextMenuStrip = _contextBObj;
			//
			// _bobject
			//
			_bobject = null;

			this.EndUpdate();
		}

		void _listView_FieldMoved(object sender, FieldMoveEventArgs e)
		{
			Row r = e.MovedObject as Row;
			BusinessObjectField field = r.Tag as BusinessObjectField;
			if ( field != null ) {
				this.BusinessObject.BusinessObjectFields.ChangePosition(field, e.Position);
			}
			refreshRoutes();
		}

		#endregion

		#region Public Members

		#region Properties

		public ColumnCollection Columns
		{
			get { return _listView.Columns; }
		}
		public RowCollection Rows
		{
			get { return _listView.Rows; }
		}
		[XmlIgnore]
		public OpenComposite.Base.Designer.ListView InnerListView
		{
			get { return _listView; }
		}
		internal SortedList<Guid, BusinessObjectField> FieldRouteAssociations
		{
			get { return _fieldRouteAssoc; }
			set { _fieldRouteAssoc = value; }
		}

		#endregion

		#region Events
		#endregion

		#region Methods
		public void AddField(BusinessObjectField field)
		{
			Row r = Rows.Add(field.Name, field.DataType);
			r.Tag = field;
			InnerListView.Refresh();
		}

		//public Row FindRow(BusinessObject bobject)
		//{
		//    foreach ( Row row in this.Rows ) {
		//        BusinessObjectField field = row.Tag as BusinessObjectField;
		//        if ( field != null && field.BusinessObject == bobject ) {
		//            return row;
		//        }
		//    }
		//    return null;
		//}
		public Row FindRow(BusinessObject bobject, Route route)
		{
			if ( _fieldRouteAssoc.ContainsKey(route.Identifier) ) {
				BusinessObjectField targetField = _fieldRouteAssoc[route.Identifier];
				foreach ( Row row in this.Rows ) {
					BusinessObjectField field = row.Tag as BusinessObjectField;
					if ( field == targetField ) return row;
				}
			} else {
				int i = 0;
				int capacity = 0;
				for ( int x = 0; x < _fieldRouteAssoc.Keys.Count; x++ ) {
					BusinessObjectField boField = _fieldRouteAssoc.Values[x];
					if ( boField.Row.RowState == DataRowState.Detached ) {
						_fieldRouteAssoc.Remove(_fieldRouteAssoc.Keys[x]);
					} else if ( boField.BusinessObjectID == bobject.ID ) {
						if ( _fieldRouteAssoc.ContainsKey(route.Identifier) ) {
							capacity++;
						} else {
							_fieldRouteAssoc.Remove(_fieldRouteAssoc.Keys[x]);
						}
					}
				}
				foreach ( Row row in this.Rows.ToArray() ) {
					BusinessObjectField field = row.Tag as BusinessObjectField;
					if ( field != null && field.BusinessObject == bobject ) {
						//if ( !_fieldRouteAssoc.ContainsKey(route.Identifier) ) {
						//    
						//}
						if ( i < capacity ) { i++; continue; }
						_fieldRouteAssoc.Add(route.Identifier, field);
						return row;
					}
				}
			}
			return null;
		}
		public void RemoveRow(Row row)
		{
			removeBORow(row);
		}

		public XmlSchemaElement GenerateXmlSchemaElement()
		{
			XmlSchemaElement thisElement = new XmlSchemaElement();
			thisElement.Name = this.Text;
			XmlSchemaComplexType complexType = new XmlSchemaComplexType();
			thisElement.SchemaType = complexType;
			XmlSchemaSequence seq = new XmlSchemaSequence();
			complexType.Particle = seq;
			if ( _bobject != null ) {
				foreach ( BusinessObjectField field in _bobject.BusinessObjectFields ) {
					if ( field.IsXmlAttribute ) {
						XmlSchemaAttribute attrib = new XmlSchemaAttribute();
						attrib.Name = field.Name;
						complexType.Attributes.Add(attrib);
					} else {
						XmlSchemaElement elem = new XmlSchemaElement();
						if ( !field.IsReference ) {
							elem.Name = field.Name;
							if ( field.MinOccurs != 1 )
								elem.MinOccursString = field.MinOccursString;
							if ( field.MaxOccurs != 1 )
								elem.MaxOccursString = field.MaxOccursString;
							elem.SchemaTypeName = new XmlQualifiedName(field.DataType, "http://www.w3.org/2001/XMLSchema");
						} else {
							if ( field.BusinessObject == null )
								//break;
								throw new NullReferenceException("field.Reference is null.");
							if ( field.Name != field.DataType && field.MaxOccurs != 1 ) {
								// create a new element for the list of current field items
								elem.Name = field.Name;
								XmlSchemaComplexType ctField = new XmlSchemaComplexType();
								elem.SchemaType = ctField;
								XmlSchemaSequence seqField = new XmlSchemaSequence();
								ctField.Particle = seqField;
								XmlSchemaElement elemField = null;
								if ( field.BusinessObject.Symbol != null ) {
									elemField = field.BusinessObject.Symbol.GenerateXmlSchemaElement();
								} else {
									if ( field.BusinessObject.Schema != null && field.BusinessObject.Schema.Items.Count > 0 )
										elemField = field.BusinessObject.Schema.Items[0] as XmlSchemaElement;
								}
								if ( elemField != null ) {
									if ( field.MinOccurs != 1 )
										elemField.MinOccursString = field.MinOccursString;
									if ( field.MaxOccurs != 1 )
										elemField.MaxOccursString = field.MaxOccursString;
									seqField.Items.Add(elemField);
								}
							} else {
								elem = null;
								// create a simple element
								if ( field.BusinessObject.Symbol != null ) {
									elem = field.BusinessObject.Symbol.GenerateXmlSchemaElement();
								} else {
									if ( field.BusinessObject.Schema != null && field.BusinessObject.Schema.Items.Count > 0 )
										elem = field.BusinessObject.Schema.Items[0] as XmlSchemaElement;
								}
								if ( elem != null ) {
									if ( field.MinOccurs != 1 )
										elem.MinOccursString = field.MinOccursString;
									if ( field.MaxOccurs != 1 )
										elem.MaxOccursString = field.MaxOccursString;
								}
							}
						}
						if ( elem != null )
							seq.Items.Add(elem);
					}
				}
			}
			return thisElement;
		}
		#endregion

		#region Overrides
		public override bool CanFocused
		{
			get { return true; }
		}
		public override bool CanMove
		{
			get { return true; }
		}
		public override bool CanSelect
		{
			get { return true; }
		}
		public override bool IsContainer
		{
			get { return false; }
		}
		public override bool NoClip
		{
			get
			{
				return true;
			}
		}

		public override void Dispose()
		{
			this._bobject = null;

			base.Dispose();
		}
		public override void Paint(System.Windows.Forms.PaintEventArgs pe)
		{
			base.Paint(pe);
		}

		public override object GetDragObject(Point location, MouseButtons button)
		{
			return this;
		}
		public override void DropObject(object obj, Point location, MouseButtons button)
		{
			BusinessObjectSymbol bosym = obj as BusinessObjectSymbol;
			Noun noun = obj as Noun;

			if ( bosym != null && bosym.RepositoryItem is BusinessObject ) {
				BusinessObjectField f = _bobject.BusinessObjectFields.Add((BusinessObject)bosym.RepositoryItem);

				if ( f != null ) {
					f.Name = bosym.Text;
					this.AddField(f);

					this._listView.Refresh();
					if ( this.RepositoryItem.ID != bosym.RepositoryItem.ID ) {
						if ( !this.DesignerViewControl.DesignerControls.ContainsName(bosym) ) {
							AddSymbolAsChild(this, bosym, 0);
						} else {
							foreach ( DesignerControl dc in this.DesignerViewControl.DesignerControls ) {
								if ( dc is BusinessObjectSymbol ) {
									if ( dc.Name == bosym.Name ) {
										bosym = dc as BusinessObjectSymbol;
										break;
									}
								}
							}
							Route r = this.DesignerViewControl.AddRoute(this, bosym);
							r.Removed += new EventHandler(route_Removed);
						}
					}
				} else {
					MessageBox.Show("Element already exists in this business object", "Add field", MessageBoxButtons.OK, MessageBoxIcon.Information);
				}
			} else if ( noun != null ) {
				BusinessObjectField f = _bobject.BusinessObjectFields.Add(noun);
				if ( f != null ) {
					this.AddField(f);
				} else {
					MessageBox.Show("Element already exists in this business object", "Add field", MessageBoxButtons.OK, MessageBoxIcon.Information);
				}
			}
		}

		/// <summary>
		/// Recursivly adds the BusinessObjectSymbol 'child' to the BusinessObjectSymbol 'parent' 
		/// </summary>
		/// <param name="parent">The parent.</param>
		/// <param name="child">The child.</param>
		/// <param name="heightModifier">The height modifier for positioning the child elements.</param>
		public void AddSymbolAsChild(BusinessObjectSymbol parent, BusinessObjectSymbol child, int heightModifier)
		{
			parent.DesignerViewControl.AddDesignerControl(child);
			//child.Location = new Point(parent.Location.X + parent.Width, parent.Location.Y);
			child.Location = new Point(parent.Right + 50, parent.Top + ( heightModifier ) * 220);
			//child.Location = new Point(parent.Width, 0);
			Route r = parent.DesignerViewControl.AddRoute(parent, child);
			r.Removed += new EventHandler(route_Removed);

			int modifier = 0;
			foreach ( BusinessObjectField field in child._bobject.BusinessObjectFields ) {
				if ( field.BusinessObject != null ) {
					DesignerControl ctrl = Global.Data.RepositoryService.CreateDesignerControl(field.BusinessObject);
					BusinessObjectSymbol subSymbol = ctrl as BusinessObjectSymbol;
					if ( subSymbol == null ) continue;
					AddSymbolAsChild(child, subSymbol, modifier);
					modifier++;
				}
			}
		}

		private bool hasRoute(BusinessObjectSymbol start, BusinessObjectSymbol end)
		{
			return this.DesignerViewControl.DesignerControls.Routes.Exists(delegate(Route r)
				{
					if ( ( r.EndControl == end && r.StartControl == start ) ||
						( r.StartControl == end && r.EndControl == start ) ) return true;
					return false;
				});
		}

		private void route_Removed(object sender, EventArgs e)
		{
			//Route r = sender as Route;

			//if ( r == null ) return;
			//foreach ( Row row in this.Rows ) {
			//    if ( _bobject != null && row.Items[1].ToString() == r.EndControl.Name ) {
			//        bool b = _bobject.BusinessObjectFields.Remove((BusinessObjectField)row.Tag);
			//        this.Rows.Remove(row);
			//        return;
			//    }
			//}

		}

		public override bool IsDropAllowed(object obj, Point location, MouseButtons button)
		{
			if ( obj is BusinessObjectSymbol ) {
				return obj != this && ( obj as BusinessObjectSymbol ).RepositoryItem != this.RepositoryItem;
			} else if ( obj is Noun ) {
				return true;
			} else {
				return false;
			}
		}

		public override object GetService(Type serviceType)
		{
			if ( _bobject != null )
				return _bobject.GetService(serviceType);
			else
				return base.GetService(serviceType);
		}

		#region IConnector
		public override Point GetRouteStart(RouteDockDirection dock, Route route)
		{
			Point pt = Point.Empty;
			Rectangle b = this.GetPaintBounds();
			BusinessObjectSymbol bos = route.EndControl as BusinessObjectSymbol;
			if ( bos != null && bos.RepositoryItem is BusinessObject ) {
				Row row = this.FindRow((BusinessObject)bos.RepositoryItem, route);
				if ( row != null ) {
					Rectangle rUp = this.InnerListView.RectangleToDesignerView(this.InnerListView.UpButtonRectangle);
					Rectangle rDown = this.InnerListView.RectangleToDesignerView(this.InnerListView.DownButtonRectangle);
					if ( row.Bounds == Rectangle.Empty ) {
						pt = new Point(b.Right, rUp.Bottom);
					} else if ( row.Bounds.Bottom > rDown.Top ) {
						pt = new Point(b.Right, rDown.Top + 1);
					} else {
						pt = new Point(b.Right, row.Bounds.Top + ( row.Bounds.Height / 2 ) + 1);
					}
				} else {
					if ( this.Rows != null && this.Rows.Count > 0 ) {
						if ( !bos.Selected ) {
							// seems not to work very well
							//bos.Remove();
						}
					}
				}
			}
			if ( pt == Point.Empty ) {
				pt = new Point(b.Right, b.Top + this.NameTextBox.Height / 2);
			} else {
			}
			return pt;
		}
		public override Point GetRouteEnd(RouteDockDirection dock, Route route)
		{
			Rectangle b = this.GetPaintBounds();
			return new Point(b.Left, b.Top + this.NameTextBox.Height / 2 + 3);
		}
		#endregion

		#region IConnectorFactory
		public override bool CreateRouteStart(DesignerControl controlEnd, out IConnector connector,
			out System.Drawing.Drawing2D.LineCap cap, out System.Drawing.Drawing2D.CustomLineCap customcap,
			out RouteDockDirection dockStart, out RouteDockDirection dockEnd, out bool useStartConnectorAsRouteStart)
		{
			bool ok = base.CreateRouteStart(controlEnd,
				out connector, out cap, out customcap, out dockStart, out dockEnd, out useStartConnectorAsRouteStart);

			cap = System.Drawing.Drawing2D.LineCap.RoundAnchor;
			customcap = null;

			dockStart = RouteDockDirection.Right;
			dockEnd = RouteDockDirection.Left;

			return ok;
		}
		public override bool CreateRouteEnd(DesignerControl controlStart, out IConnector connector,
			out System.Drawing.Drawing2D.LineCap cap, out System.Drawing.Drawing2D.CustomLineCap customcap,
			out RouteDockDirection dockStart, out RouteDockDirection dockEnd, out bool useEndConnectorAsRouteEnd)
		{
			bool ok = base.CreateRouteEnd(controlStart,
				out connector, out cap, out customcap, out dockStart, out dockEnd, out useEndConnectorAsRouteEnd);

			dockStart = RouteDockDirection.Right;
			dockEnd = RouteDockDirection.Left;

			return ok;
		}
		#endregion

		#endregion

		#region IXmlSerializable Members

		public override XmlSchema GetSchema()
		{
			return null;
		}

		public override void ReadXml(XmlReader reader)
		{
			RepositoryService repSvc = (RepositoryService)this.GetService(typeof(RepositoryService));
			if ( repSvc == null )
				throw new NullReferenceException("RepositoryService not available.");

			System.ComponentModel.BooleanConverter bc = new System.ComponentModel.BooleanConverter();
			while ( reader.Read() ) {
				switch ( reader.Name ) {
					case "BusinessObject":
						if ( reader.MoveToAttribute("id") && reader.ReadAttributeValue() )
							this.RepositoryItem = repSvc.GetItem(ItemType.BObject, int.Parse(reader.Value), false);
						if ( reader.MoveToAttribute("isMainControl") && reader.ReadAttributeValue() )
							if ( reader.Value == true.ToString() && this.DesignerViewControl != null )
								this.DesignerViewControl.MainControl = this;
						if ( reader.MoveToAttribute("isRef") && reader.ReadAttributeValue() )
							this.IsReference = (bool)bc.ConvertFromString(reader.Value);
						break;
					default:
						ReadStandardProperties(reader);
						break;
				}
				//reader.Read(); // Read the start tag.
				//if ( reader.IsStartElement() )  // Handle nested elements.
				//    Console.Write("\r\n<{0}>", reader.Name);
			}
		}

		public override void WriteXml(XmlWriter writer)
		{
			System.ComponentModel.BooleanConverter bc = new System.ComponentModel.BooleanConverter();
			WriteStandardProperties(writer);

			BusinessObject bo = this.RepositoryItem as BusinessObject;
			if ( bo != null ) {
				writer.WriteStartElement("BusinessObject");
				writer.WriteAttributeString("id", bo.ID.ToString());
				writer.WriteAttributeString("name", bo.Name);
				if ( this.DesignerViewControl.MainControl == this )
					writer.WriteAttributeString("isMainControl", true.ToString());
				else
					writer.WriteAttributeString("isMainControl", false.ToString());
				writer.WriteAttributeString("isRef", bc.ConvertToString(this.IsReference));
				writer.WriteEndElement();
			}
		}

		#endregion

		#region IRepositoryItemSymbol Members

		public bool SaveHierarchy
		{
			get { return true; }
		}

		private bool _isReference = false;
		public bool IsReference
		{
			get { return _isReference; }
			set { _isReference = value; }
		}

		public bool CanBeMainControl
		{
			get { return true; }
		}
		public IRepositoryItem RepositoryItem
		{
			get { return _bobject; }
			set
			{
				_bobject = value as BusinessObject;
				if ( _bobject != null ) {
					_bobject.ItemChanged += new OpenComposite.EII.Services.RepositoryChangedEventHandler(_bobject_ItemChanged);
					_bobject.Symbol = this;
				}
				doBObjectChanged();
			}
		}

		void _bobject_ItemChanged(object sender, OpenComposite.EII.Services.RepositoryChangedEventArgs e)
		{
			if ( e.Member != null && e.Member.Name == "Name" && e.NewValue != null ) {
				this.Text = e.NewValue.ToString();
			}
		}

		public void Load(int idRepository, int idDomain)
		{
			//_bobject.Reload();
			//foreach ( BusinessObjectField field in _bobject.BusinessObjectFields ) {
			//    this.AddField(field);
			//}
			//foreach ( BusinessObjectField field in _bobject.BusinessObjectFields ) {
			//    if ( field.IsReference ) {
			//        foreach ( DesignerControl dc in this.DesignerViewControl.DesignerControls ) {
			//            if ( dc is BusinessObjectSymbol && dc.Text == field.DataType ) {
			//                field.BusinessObject = ((BusinessObjectSymbol)dc).RepositoryItem as BusinessObject;
			//                break;
			//            }
			//        }
			//    }
			//}
		}
		public bool Save(int idRepository, int idDomain)
		{
			if ( _bobject == null )
				return false;

			Global.Data.DeleteRepositoryChildHierarchy(_bobject);
			generateXmlSchema();
			//_alreadyAddedBusinessObjects.Clear();
			//addSubObjectHierarchy(_bobject);
			return _bobject.Save();
		}

		public bool Delete(bool bAsk)
		{
			if ( _bobject == null )
				return true;

			return _bobject.Delete(bAsk);
		}

		#endregion

		internal BusinessObject BusinessObject
		{
			get { return _bobject; }
		}

		#endregion

		#region Protected Members

		#region Overrides

		protected override void OnTextChanged(EventArgs e)
		{
			if ( _bobject != null ) {
				_bobject.Name = this.Text;
				this.Name = this.Text;
			}
			base.OnTextChanged(e);
		}

		protected override Rectangle CalculateClientArea()
		{
			Rectangle r = this.Bounds;
			r.Inflate(-1, -1);
			return r;
		}

		protected override void OnLostFocus(EventArgs e)
		{
			base.OnLostFocus(e);
			_bAutoLocate = false;
		}

		protected override void OnSizeChanged(EventArgs e)
		{
			autoLocate();
			base.OnSizeChanged(e);
		}

		protected override void OnLocationChanged(EventArgs e)
		{
			try {
				if ( !_bAutoLocate ) {
					autoLocate();
				}
			} finally {
				_bAutoLocate = false;
			}
			base.OnLocationChanged(e);
		}

		private bool _bAutoLocate = false;
		private bool _bNoMoving = false;
		private const int _autoLocateWidthSpace = 50;
		private const int _autoLocateHeightSpace = 40;
		private void autoLocate()
		{
			try {
				if ( this.DesignerViewControl == null || this.DesignerViewControl.DesignerControls == null ) return;
				foreach ( DesignerControl ctrl in this.DesignerViewControl.DesignerControls ) {
					if ( ctrl == this ) continue;
					if ( ctrl is Route ) continue;
					BusinessObjectSymbol boCtrl = ctrl as BusinessObjectSymbol;
					if ( boCtrl == null ) continue;
					Rectangle thisBounds = this.Bounds;
					thisBounds.Inflate(_autoLocateWidthSpace, _autoLocateHeightSpace);
					if ( ctrl.Bounds.IntersectsWith(thisBounds) ) {
						// if alt-key is pressed, the other Control is fixed
						bool bNoMoving = ( Form.ModifierKeys & Keys.Alt ) == Keys.Alt;
						// up-down adjusting if Controls are on same X-Position
						if ( ctrl.Bounds.Left == this.Bounds.Left ) {
							if ( !_bNoMoving && bNoMoving ) {
								// this will keep the other control from autolocating
								// this Control (leading to an endless loop)
								boCtrl._bNoMoving = true;
								boCtrl.OnLocationChanged(EventArgs.Empty);
								boCtrl._bNoMoving = false;
								continue;
							}
							_bAutoLocate = true;
							if ( ctrl.Top < this.Top ) {
								ctrl.Location = new Point(this.Location.X, this.Top - ctrl.Height - _autoLocateHeightSpace);
							} else {
								ctrl.Location = new Point(this.Location.X, this.Bounds.Bottom + _autoLocateHeightSpace);
							}
						} else {
							if ( !_bNoMoving && bNoMoving ) {
								// this will keep the other control from autolocating
								// this Control (leading to an endless loop)
								boCtrl._bNoMoving = true;
								boCtrl.OnLocationChanged(EventArgs.Empty);
								boCtrl._bNoMoving = false;
								continue;
							}
							_bAutoLocate = true;
							if ( ctrl.Left < this.Left ) {
								ctrl.Location = new Point(this.Left - ctrl.Width - _autoLocateWidthSpace, ctrl.Location.Y);
							} else {
								ctrl.Location = new Point(this.Bounds.Right + _autoLocateWidthSpace, ctrl.Location.Y);
							}
						}
					}
				}
			} catch {
			}
			return;
		}

		#endregion

		#endregion

		#region Private Members

		#region Variables

		private int _iHeaderHeight = 30;

		private OpenComposite.Base.Designer.ListView _listView;
		private ContextMenuStrip _contextList;
		private ContextMenuStrip _contextBObj;
		private SortedList<Guid, BusinessObjectField> _fieldRouteAssoc = new SortedList<Guid, BusinessObjectField>();
		private List<BusinessObject> _alreadyAddedBusinessObjects = new List<BusinessObject>();
		private BusinessObject _bobject;

		#endregion

		#region Methods

		private void addSubObjectHierarchy(BusinessObject bobject)
		{
			_alreadyAddedBusinessObjects.Add(bobject);
			foreach ( BusinessObjectField field in _bobject.BusinessObjectFields ) {
				if ( field.BusinessObjectID > 0 && !_alreadyAddedBusinessObjects.Contains(field.BusinessObject) ) {
					Global.Data.AddRepositoryHierarchy(bobject, field.BusinessObject, Global.Status.CurrentRepositoryId);
					addSubObjectHierarchy(field.BusinessObject);
				}
			}
		}

		private bool showEditForm(ref BusinessObjectField field)
		{
			bool bOK = false;
			int idDomain = 0;
			int idRepository = 0;
			if ( this.DesignerViewControl.DesignController is DesignController ) {
				DesignController dc = (DesignController)this.DesignerViewControl.DesignController;
				idDomain = dc.DomainID;
				idRepository = dc.RepositoryID;
			}
			FormBusinessObjectField frm = new FormBusinessObjectField(this, idRepository, idDomain);
			frm.NounName = field.Name;
			frm.DataType = field.DataType;
			frm.MinOccurs = field.MinOccurs;
			frm.MaxOccurs = field.MaxOccurs;
			if ( field.IsReference ) {
				frm.Reference = field.BusinessObject;
			}
			if ( frm.ShowDialog() == DialogResult.OK ) {
				if ( frm.BusinessObject != null ) {
					field.BusinessObject = frm.BusinessObject;
					addConnectedBusinessObjectSymbol(frm.BusinessObject);
				} else if ( frm.Reference != null ) {
					field.BusinessObject = frm.Reference;
					addConnectedBusinessObjectSymbol(frm.Reference);
				} else if ( frm.Noun != null ) {
					field.Noun = frm.Noun;
				} else if ( !string.IsNullOrEmpty(frm.NounName) ) {
					RepositoryService repSvc = (RepositoryService)this.GetService(typeof(RepositoryService));
					DataTable dt = Global.Data.SearchRepositoryItems(Global.Status.CurrentDomainId,
						ItemType.Noun, frm.NounName, null, true);
					if ( dt != null && dt.Rows.Count > 0 ) {
						field.Noun = repSvc.GetItem<Noun>((int)dt.Rows[0]["id"]);
					}
					if ( field.Noun == null ) {
						IRepositoryItem parentItem = null;
						field.Noun = repSvc.GetNewItem<Noun>(false, ref parentItem);
						field.Noun.Name = frm.NounName;
						field.Noun.DataType = frm.DataType;
						field.Noun.Save();
						Global.Data.AddRepositoryItemToDomainFolder(Global.Status.CurrentDomainId, field.Noun);
					}
				}
				field.Name = frm.NounName;
				//field.DataType = frm.DataType;
				field.MinOccurs = frm.MinOccurs;
				field.MaxOccurs = frm.MaxOccurs;

				bOK = true;
			}
			return bOK;
		}

		private void refreshRoutes()
		{
			this.BeginUpdate();
			try {
				//for ( int i = 0; i < DesignerViewControl.DesignerControls.Routes.Count; i++ ) {
				//    Route route = DesignerViewControl.DesignerControls.Routes[i];
				//    if ( route.StartControl == this ) {
				//        route.Remove();
				//        _fieldRouteAssoc.Remove(route.Identifier);
				//        DesignerViewControl.AddRoute(route.StartControl, route.EndControl);
				//    } else { }
				//}
				foreach ( Route route in DesignerViewControl.DesignerControls.Routes.ToArray() ) {
					if ( route.StartControl == this ) {
						route.Remove();
						_fieldRouteAssoc.Remove(route.Identifier);
						DesignerViewControl.AddRoute(route.StartControl, route.EndControl);
					}
				}
			} catch { } finally {
				this.EndUpdate();
			}
		}

		private void addConnectedBusinessObjectSymbol(BusinessObject bobject)
		{
			BusinessObjectSymbol bosym = new BusinessObjectSymbol();
			bosym.RepositoryItem = bobject;
			bosym.Location = this.Location;
			if ( this.RepositoryItem.ID != bosym.RepositoryItem.ID ) {
				if ( !this.DesignerViewControl.DesignerControls.ContainsName(bosym) ) {
					this.DesignerViewControl.AddDesignerControl(bosym);
					bosym.Location = new Point(bosym.Location.X + this.Width + 50, bosym.Location.Y);
					Route r = this.DesignerViewControl.AddRoute(this, bosym);
					r.Removed += new EventHandler(route_Removed);
				}
			}
		}

		private void doBObjectChanged()
		{
			if ( _bobject != null && _bobject.ID > 0 ) {
				this.Text = _bobject.Name;
				foreach ( BusinessObjectField f in _bobject.BusinessObjectFields )
					this.AddField(f);
			} else {
				this.Rows.Clear();
			}
		}

		private void generateXmlSchema()
		{
			if ( _bobject.BusinessObjectFields == null || _bobject.BusinessObjectFields.Count == 0 )
				return;

			XmlSchema schema = new XmlSchema();
			XmlSchemaElement root = this.GenerateXmlSchemaElement();
			schema.TargetNamespace = "http://www.OpenComposite.com/canonical_document";
			schema.Namespaces.Add("tns", "http://www.OpenComposite.com/canonical_document");
			schema.Namespaces.Add("", "http://www.OpenComposite.com/canonical_document");
			schema.AttributeFormDefault = XmlSchemaForm.Unqualified;
			schema.ElementFormDefault = XmlSchemaForm.Qualified;
			schema.Items.Add(root);
			//schema.TargetNamespace = "http://www.OpenComposite.com/businessobjects/";

			_bobject.Schema = schema;
		}
		#endregion

		#region Event Handlers

		private void _listView_GotFocus(object sender, EventArgs e)
		{
			//this.Select();
			//_listView.SelectionFrame = this.SelectionFrame;
		}

		private void contextList_EditField(object sender, EventArgs e)
		{
			if ( InnerListView.SelectedIndex < 0 )
				return;

			Row r = _listView.Rows[InnerListView.SelectedIndex];
			if ( r != null && r.Tag is BusinessObjectField ) {
				// WORKAROUND: save bobj so we can create child business object references
				IController c = this.DesignerViewControl.DesignController as IController;
				if ( c != null )
					c.Save();
				// END WORKAROUND
				BusinessObjectField field = (BusinessObjectField)r.Tag;
				BusinessObject boRef = field.BusinessObject;
				if ( showEditForm(ref field) ) {
					r[0] = field.Name;
					r[1] = field.DataType;
					if ( boRef != null && field.DataType != boRef.Name ) {
						this.DesignerViewControl.RemoveRoute(this, boRef.Symbol);
						this.DesignerViewControl.DesignerControls.Remove(boRef.Symbol);
					}
					InnerListView.Refresh();
				}
			}
		}
		private void contextList_NewField(object sender, EventArgs e)
		{
			// WORKAROUND: save bobj so we can create child business object references
			IController c = this.DesignerViewControl.DesignController as IController;
			if ( c != null )
				c.Save();
			// END WORKAROUND
			BusinessObjectField field = _bobject.CreateNewField();
			if ( showEditForm(ref field) ) {
				AddField(field);
				_bobject.BusinessObjectFields.Add(field);
				InnerListView.Refresh();
			}
		}
		private void contextList_RemoveField(object sender, EventArgs e)
		{
			if ( this.InnerListView.SelectedIndex < 0 )
				return;

			Row r = InnerListView.Rows[InnerListView.SelectedIndex];
			//if ( r != null && r.Tag is BusinessObjectField ) {
			//    BusinessObjectField field = (BusinessObjectField)r.Tag;
			//    BusinessObject boRef = field.BusinessObject;
			//    if ( boRef != null ) {
			//        this.DesignerViewControl.RemoveRoute(this, boRef.Symbol);
			//        //this.DesignerViewControl.DesignerControls.Remove(boRef.Symbol);
			//    }
			//    _bobject.BusinessObjectFields.Remove(field);
			//}
			//this.Rows.RemoveAt(this.InnerListView.SelectedIndex);
			removeBORow(r);
			this.InnerListView.SelectedIndex = -1;
			refreshRoutes();
		}
		private void removeBORow(Row row)
		{
			if ( row == null ) return;

			BusinessObjectField field = row.Tag as BusinessObjectField;
			if ( field != null ) {
				BusinessObject boRef = field.BusinessObject;
				if ( boRef != null ) {
					//try {
					//    _fieldRouteAssoc.RemoveAt(_fieldRouteAssoc.IndexOfValue(field));
					//} catch { _fieldRouteAssoc.Clear(); }
					this.DesignerViewControl.RemoveRoute(this, boRef.Symbol);
				}
				_bobject.BusinessObjectFields.Remove(field);
			}
			this.Rows.Remove(row);
		}
		private void contextList_MoveUpField(object sender, EventArgs e)
		{
			if ( this.InnerListView.SelectedIndex < 0 ) return;

			int pos = InnerListView.SelectedIndex;
			Row r = Rows[InnerListView.SelectedIndex];
			BusinessObjectField f = r.Tag as BusinessObjectField;
			_bobject.BusinessObjectFields.ChangePosition(f, pos - 1);
			Rows.Remove(r);
			Rows.Insert(pos - 1, r);
			this.InnerListView.SelectedIndex = pos - 1;
			refreshRoutes();
		}
		private void contextList_MoveDownField(object sender, EventArgs e)
		{
			if ( this.InnerListView.SelectedIndex < 0 )
				return;

			int pos = InnerListView.SelectedIndex;
			Row r = Rows[InnerListView.SelectedIndex];
			BusinessObjectField f = r.Tag as BusinessObjectField;
			_bobject.BusinessObjectFields.ChangePosition(f, pos + 1);
			Rows.Remove(r);
			Rows.Insert(pos + 1, r);
			this.InnerListView.SelectedIndex = pos + 1;
			refreshRoutes();
		}

		private void contextList_Opening(object sender, System.ComponentModel.CancelEventArgs e)
		{
			bool isFirst = ( InnerListView.SelectedIndex == 0 );
			bool isLast = ( InnerListView.SelectedIndex == InnerListView.Rows.Count - 1 );
			bool canEditRemove = InnerListView.SelectedIndex >= 0;

			_contextList.Items[0].Enabled = canEditRemove;
			_contextList.Items[3].Enabled = canEditRemove;
			_contextList.Items[5].Enabled = !isFirst;
			_contextList.Items[6].Enabled = !isLast;
		}


		private void contextBObj_Remove(object sender, EventArgs e)
		{
			if ( this.DesignerViewControl.MainControl == this ) return;

			DesignerControl[] ctrls = this.GetPredecessors();
			foreach ( DesignerControl ctrl in ctrls ) {
				BusinessObjectSymbol bos = ctrl as BusinessObjectSymbol;
				if ( bos != null ) {
					List<Row> rowsToRemove = new List<Row>();
					foreach ( Row row in bos.Rows ) {
						BusinessObjectField bof = row.Tag as BusinessObjectField;
						if ( bof != null && bof.BusinessObjectID == this._bobject.ID ) {
							rowsToRemove.Add(row);
						}
					}
					foreach ( Row row in rowsToRemove ) {
						bos.RemoveRow(row);
					}
				}
			}
			this.Remove();
		}
		private void contextBObj_Delete(object sender, EventArgs e)
		{
			if ( this.DesignerViewControl.MainControl == this )
				return;

			if ( this.Delete(true) )
				this.Remove();
		}

		private void contextBObj_Opening(object sender, System.ComponentModel.CancelEventArgs e)
		{
			if ( this.DesignerViewControl.MainControl == this )
				e.Cancel = true;
		}


		#endregion

		#endregion
	}
}
// ***** Additional Informations *****
//
// Context Menu of Field List:
//		|Edit Field...
//		|New Field...
//		|---------
//		|Remove Field
//		|---------
//	   ^|Move Up
//	   v|Move Down
//
// Context Menu of Business Object:
//		|Remove Business Object
